import { defineStore } from 'pinia';
import { getToken, removeToken, setToken } from '../utils/token-utils';
import { ElMessage } from 'element-plus'
import type { RouteRecordRaw } from 'vue-router';
import type { reqUserInFoReturnType, reqLoginParamType } from "@/api/userInfo"
import { requestLogin, requestUserInfo, requestLogout } from "@/api/userInfo"

//引入所有的路由表
import { staticRoutes, allAsyncRoutes, anyRoute } from "@/router/routes"
//引入路由器对象
import router from "@/router"
//引入深拷贝
import cloneDeep from "lodash/cloneDeep"

//1.封装函数获取当前用户有权限访问的路由数据
//传入动态路由表和当前用户的菜单权限表，目的是为了得到用户有权访问的路由表然后插入到静态路由表中
const userAllStaticRoutes = (allAsyncRoutes: RouteRecordRaw[], powerRoutes: string[]) => {
  return allAsyncRoutes.filter((item) => {
    //判断一级路由有权限就保留下来
    if (powerRoutes.includes(item.name as string)) {
      //递归判断一级路由内的子路由，如果子路由有权限直接替换子路由
      if (item.children && item.children.length > 0) {
        item.children = userAllStaticRoutes(item.children, powerRoutes)
      }
      return true
    }
  })
}

//2.封装函数把过滤后的动态路由表，和任意路由表全部放入静态路由表中
const addRoutes = (routes: RouteRecordRaw[]) => {
  //因为静态路由表已经作用于app应用实例了，在修改静态路由表只会改变菜单那栏
  //所以我们需要使用addRoute方法向已经注册的路由器中添加新的路由
  routes.forEach((item) => {
    router.addRoute(item)
  })
}

//3.封装函数退出登录后清空上一个用户的路由
const deleteRoutes = (routes: RouteRecordRaw[]) => {
  //先把全部路由删除
  routes.forEach((item) => {
    router.removeRoute(item.name as string)
  })

  //在添加静态路由
  staticRoutes.forEach((item) => {
    router.addRoute(item)
  })
}


/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */
//定义用户信息模块的数据类型
export interface userInfoStateType {
  token: string;
  userInfo: reqUserInFoReturnType;
  menuRoutes: RouteRecordRaw[];
}
export const useUserInfoStore = defineStore('userInfo', {
  //定义用户信息的数据
  state: (): userInfoStateType => ({
    token: (getToken() as string) || '',
    userInfo: {
      routes: [],
      buttons: [],
      roles: [],
      name: "",
      avatar: "",
    },
    //把静态路由表保存起来,侧边栏其实是拿到这个路由表,然后遍历生成侧边栏元素的
    menuRoutes: staticRoutes
  }),

  actions: {
    //1.登录的方法
    async login(loginParams: reqLoginParamType) {
      try {
        //发送登录请求
        const result = await requestLogin(loginParams)
        //把请求回来的token保存到state
        this.token = result.token
        //设置持久化
        setToken(this.token)
      } catch (e) {
        //如果将来调用这个login方法时,请求出现问题，则返回一个失败的promise实例，在哪调用的这个login 再哪里处理
        return Promise.reject(e)
      }
    },

    //2.获取用户信息的方法
    async getInfo() {
      try {
        //发送用户信息请求
        const result = await requestUserInfo()
        //把数据保存到state
        this.userInfo = result

        //<1>.获取用户信息之后拿到当前用户有权访问的路由表（菜单）
        //从权限低的用户切换到权限高的用户，因为动态路由中的childer重新赋值过，可能会缺少,所以我们深拷贝动态路由 
        const newStaticRoutes = userAllStaticRoutes(cloneDeep(allAsyncRoutes), result.routes)

        //<2>.把新的静态路由和任意路由插入到已经注册的静态路由中
        addRoutes(newStaticRoutes.concat(anyRoute))

        //<3>.重新给menuRoutes赋值渲染出侧边栏
        this.menuRoutes = staticRoutes.concat(newStaticRoutes, anyRoute)


        //查看当前用户的所以路由
        console.log(router.getRoutes())


      } catch (e) {
        //抛出异常
        return Promise.reject(e)
      }
    },

    //3.退出登录的方法
    async getLogout() {
      try {
        //发送退出登录请求
        await requestLogout()
        //清除用户信息
        this.reset()

        //<4>.退出登录后把路由也清空
        const routes = router.getRoutes()
        deleteRoutes(routes)

      } catch (e) {
        //抛出异常
        return Promise.reject(e)
      }
    },

    //4.重置用户信息
    reset() {
      // 删除local中保存的token
      removeToken()
      // 提交重置用户信息的mutation
      this.token = ''
      this.userInfo = {
        routes: [],
        buttons: [],
        roles: [],
        name: "",
        avatar: "",
      }
    },

  },
});
